package com.du.cloud.service.oauth.endpoint;

import cn.hutool.core.util.StrUtil;
import com.du.cloud.common.base.utils.Result;
import com.du.cloud.security.annotation.inner.Inner;
import com.du.cloud.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.Principal;
import java.util.Map;

/**
 * Desc:
 * Author: dushuang
 * Date: 2020/5/26
 **/
@Slf4j
@RestController
@RequiredArgsConstructor
public class CustomEndpoint {

    private final ClientDetailsService clientDetailsService;

    @GetMapping(value = "hello")
    public Result hello() {
        return Result.ok("hello");
    }

    /**
     * 认证页面
     *
     * @param modelAndView
     * @param error        表单登录失败处理回调的错误信息
     * @return ModelAndView
     */
    @GetMapping(value = "token/login")
    public ModelAndView require(ModelAndView modelAndView, @RequestParam(required = false) String error) {
        modelAndView.setViewName("ftl/login");
        modelAndView.addObject("error", error);
        return modelAndView;
    }

    /**
     * 确认授权页面
     *
     * @param request
     * @param session
     * @param modelAndView
     * @return
     */
    @GetMapping(value = "token/confirm_access")
    public ModelAndView confirm(HttpServletRequest request, HttpSession session, ModelAndView modelAndView) {
        Map<String, Object> scopeList = (Map<String, Object>) request.getAttribute("scopes");
        modelAndView.addObject("scopeList", scopeList.keySet());

        Object auth = session.getAttribute("authorizationRequest");
        if (auth != null) {
            AuthorizationRequest authorizationRequest = (AuthorizationRequest) auth;
            ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
            modelAndView.addObject("app", clientDetails.getAdditionalInformation());
            modelAndView.addObject("user", SecurityUtils.getUser());
        }

        modelAndView.setViewName("ftl/confirm");
        return modelAndView;
    }

    @Autowired
    private TokenEndpoint tokenEndpoint;

    @GetMapping("/oauth/token")
    public Result getAccessToken(Principal principal,
                                 @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        return custom(tokenEndpoint.getAccessToken(principal, parameters).getBody());
    }

    @PostMapping("/oauth/token")
    public Result postAccessToken(Principal principal,
                                  @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        return custom(tokenEndpoint.postAccessToken(principal, parameters).getBody());
    }

    //自定义返回格式
    private Result<?> custom(OAuth2AccessToken accessToken) {
        DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken;
        Map<String, Object> data = token.getAdditionalInformation();
        // 过期时间(毫秒)
        data.put("expires", token.getExpiresIn() + System.currentTimeMillis()/1000);
        data.put("scope", token.getScope());
        data.put("accessToken", token.getValue());
        if (token.getRefreshToken() != null) {
            data.put("refreshToken", token.getRefreshToken().getValue());
        }
        return Result.ok(data);
    }

    @Autowired
    private ConsumerTokenServices consumerTokenServices;

    /**
     * 退出登录 并删除token
     * @param authHeader Authorization
     */
    @DeleteMapping(value = "token/logout")
    public Result<Boolean> logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
        if (StrUtil.isBlank(authHeader)) {
            return Result.ok();
        }

        String token = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim();
        return removeToken(token);
    }

    @DeleteMapping(value = "token/remove/{token}")
    @Inner
    public Result<Boolean> removeToken(@PathVariable("token") String token) {
        consumerTokenServices.revokeToken(token);
        log.info("TOKEN: {}已注销!", token);
        return Result.ok();
    }

}
